package com.filex.ads.common.utils;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.filex.ads.common.IntentNotResolvableException;
import com.filex.ads.common.Preconditions;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;

public class Intents {

    private static final Map<String, String> STORE_SCHEME_TO_URL_MAP;
    static {
        Map<String, String> tempMap = new HashMap<>();
        tempMap.put("market", "https://play.google.com/store/apps/details?%s");
        STORE_SCHEME_TO_URL_MAP = Collections.unmodifiableMap(tempMap);
    }

    private Intents() {}

    public static void startActivity(@NonNull final Context context, @NonNull final Intent intent)
            throws IntentNotResolvableException {
        Preconditions.checkNotNull(context);
        Preconditions.checkNotNull(intent);

        if (!(context instanceof Activity)) {
            intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
        }

        try {
            context.startActivity(intent);
        } catch (ActivityNotFoundException e) {
            throw new IntentNotResolvableException(e);
        }
    }

    /**
     * Adding FLAG_ACTIVITY_NEW_TASK with startActivityForResult will always result in a
     * RESULT_CANCELED, so don't use it for Activity contexts.
     */
    public static Intent getStartActivityIntent(@NonNull final Context context,
                                                @NonNull final Class clazz, @Nullable final Bundle extras) {
        final Intent intent = new Intent(context, clazz);

        if (!(context instanceof Activity)) {
            intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
        }

        if (extras != null) {
            intent.putExtras(extras);
        }

        return intent;
    }

    public static boolean deviceCanHandleIntent(@NonNull final Context context,
                                                @NonNull final Intent intent) {
        try {
            final PackageManager packageManager = context.getPackageManager();
            final List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
            return !activities.isEmpty();
        } catch (NullPointerException e) {
            return false;
        }
    }

    public static Intent intentForNativeBrowserScheme(@NonNull final Uri uri) {
        return new Intent(Intent.ACTION_VIEW, uri);
    }


    public static void launchIntentForUserClick(@NonNull final Context context,
                                                @NonNull final Intent intent, @Nullable final String errorMessage)
            throws IntentNotResolvableException {
        Preconditions.NoThrow.checkNotNull(context);
        Preconditions.NoThrow.checkNotNull(intent);

        try {
            startActivity(context, intent);
        } catch (IntentNotResolvableException e) {
            throw new IntentNotResolvableException(errorMessage + "\n" + e.getMessage());
        }
    }

    public static void launchApplicationUrl(@NonNull final Context context,
                                            @NonNull final Uri uri) throws IntentNotResolvableException {
        final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        Preconditions.checkNotNull(context);
        Preconditions.checkNotNull(uri);

        if (deviceCanHandleIntent(context, intent)) {
            launchApplicationIntent(context, intent);
        } else if (STORE_SCHEME_TO_URL_MAP.containsKey(intent.getScheme())
                && intent.getData() != null
                && !TextUtils.isEmpty(intent.getData().getQuery())) {
            // If this is a market intent and we don't have the Play Store or Amazon App Store installed,
            // create and launch an intent for the appropriate Play Store URL
            final String storeBrowserUrl = String.format(STORE_SCHEME_TO_URL_MAP.get(intent.getScheme()), intent.getData().getQuery());
            final Intent storeBrowserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(storeBrowserUrl));
            launchApplicationIntent(context, storeBrowserIntent);
        } else {
            // Deeplink+ needs this exception to know primaryUrl failed and then attempt fallbackUrl
            // See UrlAction.FOLLOW_DEEP_LINK_WITH_FALLBACK
            throw new IntentNotResolvableException("Could not handle application specific " +
                    "action: " + uri + "\n\tYou may be running in the emulator or another " +
                    "device which does not have the required application.");
        }
    }

    public static void launchApplicationIntent(@NonNull final Context context,
                                               @NonNull final Intent intent) throws IntentNotResolvableException {
        Preconditions.checkNotNull(context);
        Preconditions.checkNotNull(intent);

        if (deviceCanHandleIntent(context, intent)) {
            final String errorMessage = "Unable to open intent: " + intent;
            if (!(context instanceof Activity)) {
                intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
            }
            launchIntentForUserClick(context, intent, errorMessage);
        } else {
            if (!STORE_SCHEME_TO_URL_MAP.containsKey(intent.getScheme())) {
                launchApplicationUrl(context, getPlayStoreUri(intent));
            } else {
                throw new IntentNotResolvableException("Device could not handle neither " +
                        "intent nor market url.\nIntent: " + intent.toString());
            }
        }
    }

    @NonNull
    public static Uri getPlayStoreUri(@NonNull final Intent intent) {
        Preconditions.checkNotNull(intent);

        return Uri.parse("market://details?id=" + intent.getPackage());
    }

    public static void launchActionViewIntent(@NonNull final Context context,
                                              @NonNull final Uri uri,
                                              @Nullable final String errorMessage) throws IntentNotResolvableException {
        Preconditions.checkNotNull(context);
        Preconditions.checkNotNull(uri);

        final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        if (!(context instanceof Activity)) {
            intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
        }
        launchIntentForUserClick(context, intent, errorMessage);
    }
}
